<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="V0rnY" id="V0rnY"><span data-lake-id="ud4a2182f" id="ud4a2182f" style="color: rgb(85, 85, 85)">典型回答</span></h1>
  <p data-lake-id="ue8d05850" id="ue8d05850"><br></p>
  <p data-lake-id="uc2048df7" id="uc2048df7"><span data-lake-id="u90bf1574" id="u90bf1574">Spring中比较容易失效的就是通过</span><span data-lake-id="u4a0a8c66" id="u4a0a8c66" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">@Transactional 定义的声明式事务，他在以下几个场景中会导致事务失效，首先，就是Spring的@Transactional是基于Spring的AOP机制实现的，而AOP机制又是基于动态代理实现的。那么如果代理失效了，事务也就会失效。</span></p>
  <p data-lake-id="u695cd270" id="u695cd270"><span data-lake-id="ue1a6591a" id="ue1a6591a" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">​</span><br></p>
  <h3 data-lake-id="jRDhC" id="jRDhC"><span data-lake-id="u1c408127" id="u1c408127" style="color: rgb(85, 85, 85)">代理失效的情况</span></h3>
  <p data-lake-id="u9abbf61d" id="u9abbf61d"><span data-lake-id="uba732a1a" id="uba732a1a" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">​</span><br></p>
  <p data-lake-id="u3386b392" id="u3386b392"><br></p>
  <p data-lake-id="ubc586f65" id="ubc586f65"><span data-lake-id="uba87d618" id="uba87d618" class="lake-fontsize-12">在上面这篇中介绍过几种代理失效的情况，主要就是分为类的内部调用、final方法、static方法等。</span></p>
  <p data-lake-id="u6a348342" id="u6a348342"><span data-lake-id="ue0232d6c" id="ue0232d6c" class="lake-fontsize-12">​</span><br></p>
  <p data-lake-id="u6b173f0f" id="u6b173f0f"><span data-lake-id="ua1fbb94c" id="ua1fbb94c" class="lake-fontsize-12">所以就是以下几种情况就会失效：</span></p>
  <p data-lake-id="uf3828270" id="uf3828270"><span data-lake-id="ub6ac2774" id="ub6ac2774">​</span><br></p>
  <p data-lake-id="u589d9a7e" id="u589d9a7e"><span data-lake-id="ude21a8da" id="ude21a8da">1、@Transactional 应用在非 public 修饰的方法上</span></p>
  <p data-lake-id="u8c377a56" id="u8c377a56"><span data-lake-id="u43ba5801" id="u43ba5801">​</span><br></p>
  <pre lang="java"><code>
public class MyService {
    @Transactional
    private void doInternal() {
        System.out.println("Doing internal work...");
    }
}
</code></pre>
  <p data-lake-id="u49b3b7e3" id="u49b3b7e3"><br></p>
  <p data-lake-id="ua346d9f5" id="ua346d9f5"><span data-lake-id="u5b3bcf7f" id="u5b3bcf7f">private方法，只会在当前对象中的其他方法中调用，也就是会进行对象的自调用，这种情况是用this调用的，并不会走到代理对象，而@Transactional是基于动态代理实现的，所以代理会失效。</span></p>
  <p data-lake-id="u3f53c1cc" id="u3f53c1cc"><span data-lake-id="uaa0153ba" id="uaa0153ba">​</span><br></p>
  <p data-lake-id="ue0883e90" id="ue0883e90"><span data-lake-id="u4b544825" id="u4b544825">2、同一个类中方法调用，导致@Transactional失效</span></p>
  <p data-lake-id="uca29b638" id="uca29b638"><span data-lake-id="u8a52964e" id="u8a52964e">​</span><br></p>
  <pre lang="java"><code>
public class MyService {
    public void doSomething() {
        doInternal(); // 自调用方法
    }

  	 @Transactional
    public void doInternal() {
        System.out.println("Doing internal work...");
    }
}

</code></pre>
  <p data-lake-id="ua07ea37e" id="ua07ea37e"><span data-lake-id="u94d6e6b9" id="u94d6e6b9">​</span><br></p>
  <p data-lake-id="u8c09b629" id="u8c09b629"><span data-lake-id="ub3ab4867" id="ub3ab4867">以上，和private是一回事，因为没办法走到代理服务，所以事务会失效。</span></p>
  <p data-lake-id="u24095f9a" id="u24095f9a"><span data-lake-id="ue460aeab" id="ue460aeab">​</span><br></p>
  <p data-lake-id="ue66361d9" id="ue66361d9"><span data-lake-id="u7509e83c" id="u7509e83c">3、final、static方法</span></p>
  <p data-lake-id="u5d6e9d02" id="u5d6e9d02"><span data-lake-id="u1a84c9dc" id="u1a84c9dc">​</span><br></p>
  <p data-lake-id="ua34591d5" id="ua34591d5"><span data-lake-id="u9cb70a78" id="u9cb70a78">由于AOP是通过创建代理对象来实现的，而无法对final方法进行子类化和覆盖，所以无法拦截这些方法。</span></p>
  <p data-lake-id="ud53166c3" id="ud53166c3"><br></p>
  <p data-lake-id="u18cef438" id="u18cef438"><span data-lake-id="uf1b93e7d" id="uf1b93e7d">还有就是调用static方法，因为这类方法是属于这个类的，并不是对象的，所以无法被AOP。</span></p>
  <p data-lake-id="u7e45ba2d" id="u7e45ba2d"><span data-lake-id="uaff89095" id="uaff89095">​</span><br></p>
  <h3 data-lake-id="f47za" id="f47za"><span data-lake-id="uf9932b79" id="uf9932b79">@Transactional用的不对</span></h3>
  <p data-lake-id="u58dd7727" id="u58dd7727"><span data-lake-id="u09f5d0fa" id="u09f5d0fa"><br></span><span data-lake-id="uf38de7fe" id="uf38de7fe">1、@Transactional 注解属性 propagation 设置错误</span></p>
  <p data-lake-id="ud015779d" id="ud015779d"><span data-lake-id="u4ca4310d" id="u4ca4310d">​</span><br></p>
  <pre lang="java"><code>
@Service
public class ExampleService {
    
    @Autowired
    private ExampleRepository repository;

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void methodA() {
        repository.someDatabaseOperation();
    }

    public void methodB() {
        repository.anotherDatabaseOperation();
    }
}


@Service
public class SomeService {
    
    @Autowired
    private ExampleService exampleService;

    @Transactional
    public void doSomething() {
        // 这里执行一些业务逻辑
        exampleService.methodA(); // 这个方法由于 NOT_SUPPORTED 属性，会在非事务下执行
        exampleService.methodB();
        // ...
    }
}

</code></pre>
  <p data-lake-id="ucdcbd61f" id="ucdcbd61f"><span data-lake-id="u1c56e885" id="u1c56e885">​</span><br></p>
  <p data-lake-id="ua84384d6" id="ua84384d6"><span data-lake-id="u4b43e60f" id="u4b43e60f">以上，如果事务发生回滚，则methodA并不会回滚。因为他的propagation事不支持事务，那么他就不会一起回滚。</span></p>
  <p data-lake-id="ue0fcf18c" id="ue0fcf18c"><span data-lake-id="u371ed3fa" id="u371ed3fa">​</span><br></p>
  <p data-lake-id="ue9bfdb7e" id="ue9bfdb7e"><br></p>
  <p data-lake-id="ub1a0fc4e" id="ub1a0fc4e"><span data-lake-id="u3db61dd1" id="u3db61dd1"><br></span><span data-lake-id="u9bc3271e" id="u9bc3271e">2、@Transactional 注解属性 rollbackFor 设置错误</span></p>
  <p data-lake-id="u6fb21f26" id="u6fb21f26"><span data-lake-id="uaf388e08" id="uaf388e08">​</span><br></p>
  <pre lang="java"><code>
public class MyService {
    @Transactional(rollbackFor = RuntimeException.class)
    private void doInternal() {
        System.out.println("Doing internal work...");
    }
}
</code></pre>
  <p data-lake-id="u78504e48" id="u78504e48"><span data-lake-id="u5f4b691d" id="u5f4b691d">​</span><br></p>
  <p data-lake-id="u65d7bbb3" id="u65d7bbb3"><span data-lake-id="uf9c2eaab" id="uf9c2eaab">以上，如果发生非RuntimeException，则事务不会回滚，那么就会导致事务失效。所以需要指定为</span><code data-lake-id="u317c80a6" id="u317c80a6"><span data-lake-id="u44e616e9" id="u44e616e9">(rollbackFor = Exception.class)</span></code></p>
  <p data-lake-id="u48ba445b" id="u48ba445b"><span data-lake-id="u06d5b42e" id="u06d5b42e">​</span><br></p>
  <p data-lake-id="u95bbdb73" id="u95bbdb73"><span data-lake-id="u53c112d2" id="u53c112d2">​</span><br></p>
  <p data-lake-id="u902a0d8e" id="u902a0d8e"><span data-lake-id="ua8ae8830" id="ua8ae8830">3、用错注解</span></p>
  <p data-lake-id="ueb5b79e6" id="ueb5b79e6"><span data-lake-id="u7f9a7588" id="u7f9a7588">​</span><br></p>
  <p data-lake-id="ue19f2c04" id="ue19f2c04"><span data-lake-id="u445db1ff" id="u445db1ff">有的时候，你排查了很久，发现都没问题，但是还是不生效，然后找别人来帮你看，他上来就看了一下你用的@Transactional，发现并不是Spring中的，而是其他什么地方的，比如 javax.transaction.Transactional ，这样也会导致事务失效。</span></p>
  <p data-lake-id="ua7c0bc83" id="ua7c0bc83"><span data-lake-id="ub7e900f3" id="ub7e900f3">​</span><br></p>
  <h3 data-lake-id="ZSuS0" id="ZSuS0"><span data-lake-id="ue65fab0d" id="ue65fab0d">异常被捕获</span></h3>
  <p data-lake-id="ucde12047" id="ucde12047"><span data-lake-id="u52e9d208" id="u52e9d208"><br></span><span data-lake-id="uc81b683d" id="uc81b683d">5、异常被catch捕获导致@Transactional失效</span></p>
  <p data-lake-id="ufd5c55a5" id="ufd5c55a5"><span data-lake-id="ucf5577e9" id="ucf5577e9">​</span><br></p>
  <pre lang="java"><code>
public class MyService {
		@Transactional
    public void doSomething() {
      	try{
					doInternal(); 
        }catch(Exception e){
        	logger.error(e);
        }
    }
}
</code></pre>
  <p data-lake-id="u14b0abe8" id="u14b0abe8"><span data-lake-id="udb87b048" id="udb87b048">​</span><br></p>
  <p data-lake-id="u4939fd14" id="u4939fd14"><span data-lake-id="u8ba4e436" id="u8ba4e436">因为异常被捕获，所以就没办法基于异常进行rollback了，所以事务会失效。</span></p>
  <p data-lake-id="u5eb53d5a" id="u5eb53d5a"><span data-lake-id="u8706cee3" id="u8706cee3"><br><br></span></p>
  <h3 data-lake-id="xqT11" id="xqT11"><span data-lake-id="u0e619e07" id="u0e619e07">数据库引擎不支持事务</span></h3>
  <p data-lake-id="u51e899e5" id="u51e899e5"><span data-lake-id="u997b5131" id="u997b5131">​</span><br></p>
  <p data-lake-id="u83d6fac0" id="u83d6fac0"><span data-lake-id="u74522ebd" id="u74522ebd">这个好理解，如myisam，不支持的肯定就不行了。</span></p>
 </body>
</html>